﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using BitPortal.Models;
using System.Linq.Expressions;
using System.Collections.ObjectModel;
using System.Collections;
using BitPortal.Utils;
namespace BitPortal.Business
{
    public static partial class ProductBLL
    {
        /// <summary>
        /// Lay duong link da Rewrite
        /// </summary>
        /// <param name="cat"></param>
        /// <returns></returns>
        public static string GetSEOUrl(this Product art)
        {
            return "/Product/" + art.ProductCategory.Name.ToSeoString() + "/" + art.Name.ToSeoString() + "-pd" + art.ProductID + ".aspx";
        }
        public static string GetSEOUrl(object name, object Id)
        {
            return "/Product/" + name.ToString().ToSeoString() + "-pd" + Id + ".aspx";
        }
        public static int Insert(this Product product)
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            //Add Static
            Statistic statistic = new Statistic() { DatetimeLastModified = DateTime.Now, ViewUserIDs = "#", ViewUserIPs = "#", LikeUserIDs = "#", DislikeUserIDs = "#" };
            bitEnt.Statistics.AddObject(statistic);
            //Add Discusstion
            DiscussionGroup discussionGroup = new DiscussionGroup() { DatetimeCreated = DateTime.Now, LanguageCode = product.LanguageCode, DiscussionCount = 0 };
            bitEnt.DiscussionGroups.AddObject(discussionGroup);
            //Add Product
            product.Statistic = statistic;
            product.DiscussionGroup = discussionGroup;
            bitEnt.Products.AddObject(product);
            return bitEnt.SaveChanges();
        }

        public static Product GetByID(long productID)
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            return bitEnt.Products.SingleOrDefault(ent => ent.ProductID == productID);
        }

        public static IQueryable<Product> GetAll()
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            var list = from ent in bitEnt.Products
                       where ent.IsDeleted == false
                       //orderby ent.SortOrder descending, ent.ProductID descending
                       select ent;
            return list;
        }

        public static int DeletePermanently(long productID)
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            Product product = bitEnt.Products.SingleOrDefault(a => a.ProductID == productID);
            if (product != null)
            {
                Statistic statistic = product.Statistic;
                DiscussionGroup discussionGroup = product.DiscussionGroup;
                bitEnt.Products.DeleteObject(product);
                //Delete Statistic
                if (statistic != null)
                {
                    bitEnt.Statistics.DeleteObject(statistic);
                }
                //Delete DiscussionGroup
                if (discussionGroup != null)
                {
                    bitEnt.DiscussionGroups.DeleteObject(discussionGroup);
                }
                return bitEnt.SaveChanges();
            }
            return 0;
        }

        public static int Delete(long productID)
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            Product a = bitEnt.Products.SingleOrDefault(ent => ent.ProductID == productID);
            a.IsDeleted = true;
            return bitEnt.SaveChanges();
        }

        public static int Delete(long[] productIDs)
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            foreach (long productID in productIDs)
            {
                Product a = bitEnt.Products.SingleOrDefault(ent => ent.ProductID == productID);
                a.IsDeleted = true;
            }
            return bitEnt.SaveChanges();

        }

        public static IQueryable<Product> GetByCondition(string languageCode = null, string name = null, int? categoryID = null, bool? isNew = null, bool? isHot = null, bool? allowOrder = null, bool? isEnabled = null, int start = -1, int limit = -1, string sort = null, string dir = null)
        {
            var list = GetAll().Where(ent => (languageCode == null || ent.LanguageCode.Equals(languageCode)) &&
                    (name == null || ent.Name.Contains(name)) &&
                    (categoryID == null || ent.CategoryID == categoryID) &&
                    (isNew == null || ent.IsNew == isNew) &&
                    (isHot == null || ent.IsHot == isHot) &&
                    (allowOrder == null || ent.AllowOrder == allowOrder) &&
                    (isEnabled == null || ent.IsEnabled == isEnabled)
                );

            //Start Sorting
            if (sort != null)
            {
                var param = Expression.Parameter(typeof(Product), "ent");

                var sortExpression = Expression.Lambda<Func<Product, Object>>(Expression.Property(param, sort), param);
                if (dir == "DESC")
                {
                    list = list.OrderByDescending(sortExpression);
                }
                else
                {
                    list = list.OrderBy(sortExpression);
                }
            }
            //Start Paging
            if (start >= 0 && limit > 0)
            {
                list = list.Skip(start).Take(limit);
            }
            return list;
        }

        public static IQueryable<Product> GetByCondition<T>(string languageCode = null, string name = null, int? categoryID = null, bool? isNew = null, bool? isHot = null, bool? allowOrder = null, bool? isEnabled = null, int start = -1, int limit = -1, string sort = "SortOrder", string dir = "DESC", IQueryable<Product> fromSource = null, bool searchFromChilds = true)
        {
            if (fromSource == null) fromSource = GetAll();
            if (searchFromChilds && categoryID != null)
            {
                fromSource = GetByCategory((int)categoryID).AsQueryable();
                categoryID = null;
            }
            var list = GetAll().Where(ent => (languageCode == null || ent.LanguageCode.Equals(languageCode)) &&
                    (name == null || ent.Name.Contains(name)) &&
                    (categoryID == null || ent.CategoryID == categoryID) &&
                    (isNew == null || ent.IsNew == isNew) &&
                    (isHot == null || ent.IsHot == isHot) &&
                    (allowOrder == null || ent.AllowOrder == allowOrder) &&
                    (isEnabled == null || ent.IsEnabled == isEnabled)
                );

            //Start Sorting
            if (sort != null)
            {
                if (sort.Equals("ProductID"))
                {
                    if (dir.ToUpper() == "DESC")
                    {
                        list = list.OrderByDescending(ent => ent.ProductID);
                    }
                    else
                    {
                        list = list.OrderBy(ent => ent.ProductID);
                    }
                }
                else
                {
                    var param = Expression.Parameter(typeof(Product), "ent");
                    var sortExpression = Expression.Lambda<Func<Product, T>>(Expression.Property(param, sort), param);
                    if (dir.ToUpper() == "DESC")
                    {
                        list = list.OrderByDescending(sortExpression).ThenByDescending(ent => ent.ProductID);
                    }
                    else
                    {
                        list = list.OrderBy(sortExpression).ThenByDescending(ent => ent.ProductID);
                    }
                }
            }
            //Start Paging
            if (start >= 0 && limit > 0)
            {
                list = list.Skip(start).Take(limit);
            }
            return list;
        }

        public static List<Product> GetByCategory(int? categoryID)
        {
            if (categoryID == null) return GetAll().ToList();

            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            var list = (from ent in bitEnt.Products
                        where ent.IsDeleted == false && ent.CategoryID == categoryID
                        select ent).ToList();

            foreach (ProductCategory cate in ProductCategoryBLL.GetAllChilds(ProductCategoryBLL.GetByID((int)categoryID)))
            {
                var listProductOnChild = from ent in bitEnt.Products
                                         where ent.IsDeleted == false && ent.CategoryID == cate.CategoryID
                                         select ent;

                list = listProductOnChild.ToList().Union(list).ToList();
            }
            return list;
        }

        /// <summary>
        /// Lay danh sach san pham thuoc danh muc truyen vao hoac thuoc danh muc con cua no
        /// </summary>
        /// <param name="categoryID"></param>
        /// <param name="result"></param>
        public static void GetByCategory(int? categoryID, IQueryable<Product> result)
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            result.Union(from ent in bitEnt.Products
                         where ent.IsDeleted == false && ent.CategoryID == categoryID
                         select ent);
            foreach (ProductCategory childCate in bitEnt.ProductCategories.Where(ent => ent.ParentID == categoryID))
            {
                GetByCategory(childCate.CategoryID, result);
            }
        }

        public static int AddMedia(long productID, long mediaID, long sortOrder = 0, string title = null)
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            if (bitEnt.ProductImages.Count(ent => ent.ProductID == productID && ent.MediaID == mediaID) > 0)
            {
                throw new Exception("Media đã được thêm vào Product!");
            }
            ProductImage mg = new ProductImage()
            {
                MediaID = mediaID,
                ProductID = productID,
                SortOrder = sortOrder,
                Title = title
            };
            bitEnt.ProductImages.AddObject(mg);
            return bitEnt.SaveChanges();
        }

        public static int DeleteMedia(int productID, long mediaID)
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            ProductImage mg = bitEnt.ProductImages.SingleOrDefault(ent => (ent.ProductID == productID && ent.MediaID == mediaID));
            if (mg != null)
            {
                bitEnt.ProductImages.DeleteObject(mg);
            }
            return bitEnt.SaveChanges();
        }

        public static IQueryable<Media> GetMedia(long productID, string type = null, bool? isEnabled = null)
        {
            ExtendedBitPortalEntities bitEnt = new ExtendedBitPortalEntities();
            var listMedia = from g in bitEnt.Products
                            from gm in bitEnt.ProductImages
                            from m in bitEnt.Medias
                            where g.ProductID == productID && g.ProductID == gm.ProductID && gm.MediaID == m.MediaID
                            select m;
            return listMedia.Where(ent =>
                (type == null || ent.Type == type) &&
                (isEnabled == null || ent.IsEnabled == isEnabled)
                );

        }

        public static IQueryable<Media> GetMedia(this Product product, string type = null, bool? isEnabled = null)
        {
            return GetMedia(product.ProductID, type, isEnabled);
        }

        /// <summary>
        /// Seach fulltext tren bang nay, dat saveKeyWord = true de luu key word vao DB
        /// </summary>
        /// <param name="keyword"></param>
        /// <param name="saveKeyWord"></param>
        /// <returns></returns>
        public static List<Product> FulltextSearch(string keyword, bool saveKeyWord = true, bool addvanceSearch = true)
        {
            BitPortalEntities bitEnt = new BitPortalEntities();
            return (from a in bitEnt.Products
                    join r in FulltextSearchID(keyword, saveKeyWord, addvanceSearch) on a.ProductID equals r
                    select a).ToList();
        }

        public static List<Int64?> FulltextSearchID(string keyword, bool saveKeyWord = true, bool addvanceSearch = true)
        {
            BitPortalEntities bitEnt = new BitPortalEntities();
            List<Int64?> result = bitEnt.BitPortal_FT_Products(keyword).ToList();
            if (addvanceSearch)
            {
                var keys = KeyWordBLL.ListSameKeyWord(keyword);
                foreach (string key in keys)
                {
                    result = result.Union(FulltextSearchID(key, false, false)).ToList();
                }
            }
            if (saveKeyWord)
            {
                (new Keyword() { KeyName = keyword, ResultCount = result.Count }).Save();
            }
            return result;
        }

        /// <summary>
        /// Loc san pham theo thuoc tinh san pham
        /// </summary>
        /// <param name="properties"></param>
        /// <param name="source"></param>
        /// <returns></returns>
        public static List<Product> FilterByProperties(this List<Product> source, List<string> filters, char fiterSpliter = '-')
        {
            foreach (string filter in filters)
            {
                string[] parameters = filter.Split(fiterSpliter);
                if (parameters.Count() < 3) continue;
                ProductProperty property = ProductPropertyBLL.GetByID(parameters[0].ToInt32TryParse());
                if (property == null) continue;
                object value = parameters[2].GetValueInType(property.DataType);
                source.RemoveAll(item => item.ProductPropertyValues.Count(ent =>
                {
                    if (ent.PropertyID != property.PropertyID) return false;
                    IComparable cItem = ent.Value.GetValueInType(property.DataType) as IComparable;
                    parameters[1] = parameters[1].Trim().ToLower();
                    if (parameters[1].Equals("eq")) return cItem.Equals(value);
                    if (parameters[1].Equals("neq")) return !cItem.Equals(value);
                    if (parameters[1].Equals("gt")) return cItem.CompareTo(value) >= 0;
                    if (parameters[1].Equals("lt")) return cItem.CompareTo(value) <= 0;
                    if (parameters[1].Equals("ctn")) return cItem.ToString().IndexOf(value.ToString(), StringComparison.OrdinalIgnoreCase) >= 0;
                    if (parameters[1].Equals("stw")) return cItem.ToString().StartsWith(value.ToString(), StringComparison.InvariantCultureIgnoreCase);
                    return false;
                }) == 0);
            }
            return source;
        }
    }
}